﻿using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;

namespace Topro.Log
{
    /// <summary>
    /// 请求日志中间件
    /// </summary>
    public class HttpLogMiddleWare
    {
        #region 

        private const string ContentTypeRegexRule = @"(?i)(application\/json|(text\/plain))";
        /// <summary>
        /// 请求委托
        /// </summary>
        private readonly RequestDelegate _next;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="next">请求委托</param>
        public HttpLogMiddleWare(RequestDelegate next)
        {
            _next = next;
        }
        #endregion

        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public async Task Invoke(HttpContext context)
        {
            //请求
            var httpLogModel = await GetHttpRequst(context.Request);
            var originalBodyStream = context.Response.Body;
            var responseBodyAsText = string.Empty;
            try
            {
                using (var responseBody = new MemoryStream())
                {
                    context.Response.Body = responseBody;
                    await _next(context);
                    responseBodyAsText = await GetResponseBody(context.Response);
                    await responseBody.CopyToAsync(originalBodyStream);
                }
            }
            finally
            {
                httpLogModel.ResponseTime = DateTime.Now;
                httpLogModel.ResponseBody = responseBodyAsText;
                httpLogModel.ResponseStatusCode = context.Response.StatusCode;
                httpLogModel.ResponseContentType = context.Response.ContentType;
                httpLogModel.ResponseHeaders = GetHeadersAsString(context.Response.Headers);

                HttpLogImpl.Add(httpLogModel);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        private static async Task<HttpLog> GetHttpRequst(HttpRequest request)
        {
            //request.EnableBuffering();
            //request.EnableRewind();
            var body = request.Body;

            var requestBody = "";

            //using (var reader = new StreamReader(request.Body, encoding: Encoding.UTF8))
            //{
            //    var requestBodyxx = await reader.ReadToEndAsync();
            //}

            request.Body = body;

            var model = new HttpLog
            {
                RequestIp = GetClientIp(request),
                RequestUri = request.GetDisplayUrl(),
                RequestQueryString = request.QueryString.Value,
                RequestContentType = request.ContentType,
                RequestMethod = request.Method,
                RequestBody = requestBody,
                RequestCookies = GetCookiesAsString(request.Cookies),
                RequestHeaders = GetHeadersAsString(request.Headers),
                RequestTime = DateTime.Now,
            };
            return model;
        }

        private static async Task<string> GetResponseBody(HttpResponse response)
        {
            var result = string.Empty;

            response.Body.Seek(0, SeekOrigin.Begin);

            var responseBodyAsText = await new StreamReader(response.Body).ReadToEndAsync();

            response.Body.Seek(0, SeekOrigin.Begin);

            if (response.ContentType != null && new Regex(ContentTypeRegexRule).IsMatch(response.ContentType))
            {
                result = responseBodyAsText;
            }

            return result;
        }

        #region 获取客户端Ip
        /// <summary>
        /// 获取客户端Ip
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        private static string GetClientIp(HttpRequest request)
        {
            var remoteIpAddress = request.HttpContext.Connection.RemoteIpAddress.ToString();

            if (remoteIpAddress == "::1")
            {
                return "127.0.0.1" + ":" + request.HttpContext.Connection.RemotePort;
            }

            string result;
            try
            {
                var addressList = remoteIpAddress.Split(':');
                result = addressList[addressList.Length - 1];
            }
            catch (Exception)
            {
                return remoteIpAddress;
            }

            return result + ":" + request.HttpContext.Connection.RemotePort;
        }
        #endregion

        #region 获取头部
        /// <summary>
        /// 获取头部
        /// </summary>
        /// <param name="headers"></param>
        /// <returns></returns>
        private static string GetHeadersAsString(IHeaderDictionary headers)
        {
            var sb = new StringBuilder();
            foreach (var key in headers.Keys)
            {
                sb.Append(key + ": " + headers[key] + Environment.NewLine);
            }

            return sb.ToString();
        }
        #endregion

        #region 获取Cokies
        /// <summary>
        /// 获取Cokies
        /// </summary>
        /// <param name="cookies"></param>
        /// <returns></returns>
        private static string GetCookiesAsString(IRequestCookieCollection cookies)
        {
            var sb = new StringBuilder();
            foreach (var key in cookies.Keys)
            {
                sb.Append(key + "=" + cookies[key] + Environment.NewLine);
            }

            return sb.ToString();
        }
        #endregion
    }
}
